﻿using Coolzon.UI.Common.Widgets;
using Coolzon.UI.Core;
using Coolzon.Web.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
using Visifire.Charts;

namespace Coolzon.UI.Charts.Widgets
{
    public partial class DataChartAxisBase : DataChartBase
    {
        public DataChartAxisBase()
        {
            AxisYMaximum = 250;
            AxisYMinimum = 0;
            AxisYInterval = 50;
            AxisYLabelRows = 1;
            AxisYLabelEnable = true;
            AxisYEnabled = true;
            AxisYLineStyle = LineStyles.Solid;
            AxisYLineThickness = 1;
            AxisYLabelFontSize = 12;
            AxisYTickEnabled = true;
            AxisYTickInterval = 50;
            AxisYTickLineStyles = LineStyles.Solid;
            AxisYTickLineThickness = 1;
            AxisYLabelFontColor = new SolidColorBrush(Colors.Black);
            AxisYLogarithmBase = 10;

            AxisY2Maximum = 250;
            AxisY2Minimum = 0;
            AxisY2Interval = 50;
            AxisY2LabelRows = 1;
            AxisY2LabelEnable = true;
            AxisY2LineStyle = LineStyles.Solid;
            AxisY2LineThickness = 1;
            AxisY2LabelFontSize = 12;
            AxisY2TickEnabled = true;
            AxisY2TickInterval = 50;
            AxisY2TickLineStyles = LineStyles.Solid;
            AxisY2TickLineThickness = 1;
            AxisY2LabelFontColor = new SolidColorBrush(Colors.Black);
            AxisY2LogarithmBase = 10;

            AxisXEnabled = true;
            AxisXLineStyle = LineStyles.Solid;
            AxisXLineThickness = 1;
            AxisXIntervalType = IntervalTypes.Auto;

            AxisXLabelEnable = true;
            AxisXLabelFontSize = 12;
            AxisXLabelRows = 1;
            AxisXLabelFontColor = new SolidColorBrush(Colors.Black);
        }
        protected override void OnInit(PartContext context)
        {
            GetChart().ScrollingEnabled = false;

            base.OnInit(context);
            OnApplyXProperty();
        }
        protected override void OnApplyXProperty()
        {
            base.OnApplyXProperty();
            Chart chart = GetChart();
            if(chart == null)
            {
                return;
            }
            chart.AxesX.Clear();
            chart.AxesX.Add(getAxisX());
            chart.AxesY.Clear();
            chart.AxesY.Add(getAxisY());
            chart.AxesY.Add(getAxisY2());
        }
        protected override void OnDataBinding(DataBindingArgs args)
        {
            DataResult dataResult = args.DataResult;
            //ClearAnimation();
            //StopAnimation();
            //_animationStoryboard = new Storyboard();
            //_animationStoryboard.FillBehavior = FillBehavior.HoldEnd;
            //_animationStoryboard.Completed += _animationStoryboard_Completed;

            Chart chart = GetChart();
            double maxYValue = 0;
            double minYValue = 0;

            double max2ndYValue = 0;
            double min2ndYValue = 0;

            if (dataResult.DataSeries.Count > 0)
            {
                if (dataResult.DataSeries.Count < chart.Series.Count)
                {
                    // 从现有图表上移除多余的数据串
                    for (int itemIndex = dataResult.DataSeries.Count; itemIndex < chart.Series.Count; itemIndex++)
                    {
                        chart.Series.RemoveAt(itemIndex);
                    }
                }

                for(int index = 0; index < dataResult.DataSeries.Count; index++)
                {
                    Coolzon.Web.Models.DataSeries dataSeries = dataResult.DataSeries[index];
                    Visifire.Charts.DataSeries vfdataSeries =null;
                    if (index < chart.Series.Count)
                    {
                        vfdataSeries = chart.Series[index];
                    }
                    else
                    {
                        vfdataSeries = new Visifire.Charts.DataSeries();
                        if (LineThickness != null)
                        {
                            vfdataSeries.LineThickness = LineThickness;
                        }
                        vfdataSeries.RenderAs = GetRender(dataSeries.Id);
                        vfdataSeries.Name = dataSeries.Name;
                        vfdataSeries.LegendText = dataSeries.Name;
                        vfdataSeries.Bevel = Bevel;
                        vfdataSeries.ShowInLegend = LegendEnabled;
                        vfdataSeries.LineStyle = GetLineStyle(dataSeries.Id);
                        vfdataSeries.XValueType = this.AxisXValueType;
                        if (!string.IsNullOrEmpty(AxisXValueFormatString))
                        {
                            vfdataSeries.XValueFormatString = this.AxisXValueFormatString;
                        }
                       
                        //设置Y轴类型 Primary或者Secondary
                        if (SeriesYAxisType != null && SeriesYAxisType.ContainsKey(dataSeries.Id))
                        {
                            vfdataSeries.AxisYType = (AxisTypes)Enum.Parse(typeof(AxisTypes), SeriesYAxisType[dataSeries.Id]);
                        }
                        chart.Series.Add(vfdataSeries);
                    }

                    if (dataSeries.DataItems.Count < vfdataSeries.DataPoints.Count)
                    {
                        // 从现有图表上移除多余的数据
                        for (int itemIndex = dataSeries.DataItems.Count; itemIndex < vfdataSeries.DataPoints.Count; itemIndex++)
                        {
                            vfdataSeries.DataPoints.RemoveAt(itemIndex);
                        }
                    }

                    for(int itemIndex = 0; itemIndex < dataSeries.DataItems.Count; itemIndex++)
                    {
                        DataItem dataItem = dataSeries.DataItems[itemIndex];
                        IDataPoint datapoint = null;

                        if (itemIndex < vfdataSeries.DataPoints.Count)
                        {
                            datapoint = vfdataSeries.DataPoints[itemIndex];
                        }
                        else
                        {
                            datapoint = ResolveDataPoint();
                            datapoint.YValue = AxisYMinimum;
                            if(datapoint is DataPoint)
                            {
                                (datapoint as DataPoint).LegendText = dataItem.Name;
                                (datapoint as DataPoint).ShowInLegend = LegendEnabled;
                                SetDataPoint((datapoint as DataPoint));
                            }
                            vfdataSeries.DataPoints.Add(datapoint);
                        }
                        datapoint.Name = dataItem.Name;
                        FormatDataPoint(vfdataSeries, datapoint, dataItem.Name);
                        double dItemValue = Convert.ToDouble(dataItem.Value);
                        if (vfdataSeries.AxisYType == AxisTypes.Secondary)
                        {
                            if (dItemValue > max2ndYValue)
                            {
                                max2ndYValue = dItemValue;
                            }
                            else if (dItemValue < min2ndYValue)
                            {
                                min2ndYValue = dItemValue;
                            }
                        }
                        else
                        {
                            if (dItemValue > maxYValue)
                            {
                                maxYValue = dItemValue;
                            }
                            else if (dItemValue < minYValue)
                            {
                                minYValue = dItemValue;
                            }
                        }

                        if (datapoint is DataPoint)
                        {
                            DataPoint dataPoint = datapoint as DataPoint;
                            if (args.Reason == DataBindingReason.Active)
                            {
                                dataPoint.BeginAnimation(DataPoint.YValueProperty, null);
                                dataPoint.YValue = 0;
                                // active 从0 开始
                                DoubleAnimation animation = new DoubleAnimation(0, dItemValue, new Duration(TimeSpan.FromSeconds(XDataAnimationDuration)));
                                dataPoint.BeginAnimation(DataPoint.YValueProperty, animation, HandoffBehavior.Compose);
                            }
                            else
                            {
                                DoubleAnimation animation = new DoubleAnimation(datapoint.YValue, dItemValue, new Duration(TimeSpan.FromSeconds(XDataAnimationDuration)));
                                dataPoint.BeginAnimation(DataPoint.YValueProperty, animation, HandoffBehavior.SnapshotAndReplace);
                            }
                        }
                        else
                        {
                            datapoint.YValue = dItemValue;
                        }

                        //Storyboard.SetTarget(animation, datapoint);
                        //Storyboard.SetTargetProperty(animation, new PropertyPath(DataPoint.YValueProperty));
                        //_animationStoryboard.Children.Add(animation);
                    }
                }

                //if (_animationStoryboard != null)
                //{
                //    _animationStoryboard.Begin();
                //}
            }
            
            SetLegends(chart.Legends);

            ApplyChartColorPlate();

            AutoReviseYAxis(minYValue, maxYValue);
            AutoRevise2ndYAxis(min2ndYValue, max2ndYValue);
        }
        public void AutoReviseYAxis(double minValue, double maxValue)
        {
            if (!IsAutoReviseYAxis)
            {
                return;
            }

            double intMmultiple10 = int.MaxValue * 10.0d;
            double intMmultiple100 = int.MaxValue * 100.0d;
            double intMmultiple1000 = int.MaxValue * 1000.0d;

            // 预期的等分数
            int expectantSegmentCount = 5;

            if (AxisYMaximum != 0 && AxisYInterval != 0 && AxisYMaximum > AxisYMinimum)
            {
                double scount = (AxisYMaximum - AxisYMinimum) / AxisYInterval;
                double remainder = (AxisYMaximum - AxisYMinimum) % AxisYInterval;

                if (remainder > 0)
                {
                    expectantSegmentCount = (int)scount + 1;
                }
                else
                {
                    expectantSegmentCount = (int)scount;
                }

            }

            double yAxisMax = 0;
            double yAxisMin = 0;
            if (AxisYMaximum != 0)
            {
                yAxisMax = AxisYMaximum;
            }
            yAxisMin = AxisYMinimum;

            yAxisMax = maxValue;

            if (yAxisMax < 1)
            {
                yAxisMax = 1;
            }
            else if (yAxisMax < 10)
            {
                yAxisMax = Math.Round(yAxisMax, 0) + 1.0d;
            }
            else if (yAxisMax > intMmultiple1000)
            {
                int div = (int)(yAxisMax / 10000);
                yAxisMax = (div + 1) * 10000.0d;
            }
            else if (yAxisMax > intMmultiple100)
            {
                int div = (int)(yAxisMax / 1000);
                yAxisMax = (div + 1) * 1000.0d;
            }
            else if (yAxisMax > intMmultiple10)
            {
                int div = (int)(yAxisMax / 100);
                yAxisMax = (div + 1) * 100.0d;
            }
            else if (yAxisMax > 50)
            {
                int div = (int)(yAxisMax / 10);
                yAxisMax = (div + 1) * 10.0d;
            }

            if (yAxisMax <= yAxisMin)
            {
                yAxisMin = 0;
            }

            // 修正坐标轴
            double interval = (yAxisMax - yAxisMin) / expectantSegmentCount;

            if (interval > 1.0d)
            {
                if (interval > 5000)
                {
                    interval = Math.Round(interval / 1000 + 1.0d, 0) * 1000;
                    yAxisMax = yAxisMin + interval * expectantSegmentCount;
                }
                else if (interval > 500)
                {
                    interval = Math.Round(interval / 100 + 1.0d, 0) * 100;
                    yAxisMax = yAxisMin + interval * expectantSegmentCount;
                }
                else if (interval > 50)
                {
                    interval = Math.Round(interval / 10 + 1.0d, 0) * 10;
                    yAxisMax = yAxisMin + interval * expectantSegmentCount;
                }
                else if (interval > 10)
                {
                    interval = Math.Round(interval / 5 + 1.0d, 0) * 5;
                    yAxisMax = yAxisMin + interval * expectantSegmentCount;
                }
                else
                {
                    interval = Math.Round(interval, 0) + 1.0d;
                    yAxisMax = yAxisMin + interval * expectantSegmentCount;
                }
            }

            this.axisY.AxisMaximum = yAxisMax;
            this.axisY.AxisMinimum = yAxisMin;
            this.axisY.Interval = interval;
        }
        public void AutoRevise2ndYAxis(double minValue, double maxValue)
        {
            if (!IsAutoReviseY2Axis)
            {
                return;
            }

            double intMmultiple10 = int.MaxValue * 10.0d;
            double intMmultiple100 = int.MaxValue * 100.0d;
            double intMmultiple1000 = int.MaxValue * 1000.0d;

            // 预期的等分数
            int expectantSegmentCount = 5;

            if (AxisY2Maximum != 0 && AxisY2Interval != 0)
            {
                double scount = (AxisY2Maximum - AxisY2Minimum) / AxisY2Interval;
                double remainder = (AxisY2Maximum - AxisY2Minimum) % AxisY2Interval;

                if (remainder > 0)
                {
                    expectantSegmentCount = (int)scount + 1;
                }
                else
                {
                    expectantSegmentCount = (int)scount;
                }

            }

            double yAxisMax = 0;
            double yAxisMin = 0;
            if (AxisY2Maximum != 0)
            {
                yAxisMax = AxisY2Maximum;
            }
            yAxisMin = AxisY2Minimum;

            yAxisMax = maxValue;

            if (yAxisMax < 1)
            {
                yAxisMax = 1;
            }
            else if (yAxisMax < 10)
            {
                yAxisMax = Math.Round(yAxisMax, 0) + 1.0d;
            }
            else if (yAxisMax > intMmultiple1000)
            {
                int div = (int)(yAxisMax / 10000);
                yAxisMax = (div + 1) * 10000.0d;
            }
            else if (yAxisMax > intMmultiple100)
            {
                int div = (int)(yAxisMax / 1000);
                yAxisMax = (div + 1) * 1000.0d;
            }
            else if (yAxisMax > intMmultiple10)
            {
                int div = (int)(yAxisMax / 100);
                yAxisMax = (div + 1) * 100.0d;
            }
            else if (yAxisMax > 50)
            {
                int div = (int)(yAxisMax / 10);
                yAxisMax = (div + 1) * 10.0d;
            }

            if (yAxisMax <= yAxisMin)
            {
                yAxisMin = 0;
            }

            // 修正坐标轴
            double interval = (yAxisMax - yAxisMin) / expectantSegmentCount;

            if (interval > 1.0d)
            {
                if (interval > 5000)
                {
                    interval = Math.Round(interval / 1000 + 1.0d, 0) * 1000;
                    yAxisMax = yAxisMin + interval * expectantSegmentCount;
                }
                else if (interval > 500)
                {
                    interval = Math.Round(interval / 100 + 1.0d, 0) * 100;
                    yAxisMax = yAxisMin + interval * expectantSegmentCount;
                }
                else if (interval > 50)
                {
                    interval = Math.Round(interval / 10 + 1.0d, 0) * 10;
                    yAxisMax = yAxisMin + interval * expectantSegmentCount;
                }
                else if (interval > 10)
                {
                    interval = Math.Round(interval / 5 + 1.0d, 0) * 5;
                    yAxisMax = yAxisMin + interval * expectantSegmentCount;
                }
                else
                {
                    interval = Math.Round(interval, 0) + 1.0d;
                    yAxisMax = yAxisMin + interval * expectantSegmentCount;
                }
            }

            this.axisY2.AxisMaximum = yAxisMax;
            this.axisY2.AxisMinimum = yAxisMin;
            this.axisY2.Interval = interval;
        }
        protected void FormatDataPoint(Visifire.Charts.DataSeries dataSeries, Visifire.Charts.IDataPoint dataPoint, string xValue)
        {
            dataPoint.Name = xValue;

            if (dataSeries.XValueType == ChartValueTypes.DateTime
                || dataSeries.XValueType == ChartValueTypes.Date
                || dataSeries.XValueType == ChartValueTypes.Time)
            {
                DateTime datetime;
                if (DateTime.TryParse(xValue, out datetime))
                {
                    // 日期类型的数据
                    dataPoint.XValue = datetime;
                }
            }
            else
            {
                //每隔一定字符插入'\n'来进行换行
                if (XXValueNLCC != null && XXValueNLCC.Value > 0)
                {
                    int valueLength = xValue.Length - 1;
                    for (int i = 1; i <= (int)(valueLength / XXValueNLCC.Value); i++)
                    {
                        xValue = xValue.Insert(i * XXValueNLCC.Value + i - 1, "\n");
                    }
                }
                dataPoint.AxisXLabel = xValue;
            }
        }
        protected virtual LineStyles GetLineStyle(string dataSeriesName)
        {
            return LineStyles.Solid;
        }

        protected virtual IDataPoint ResolveDataPoint()
        {
            return new DataPoint();
        }
    }
}
